module Addressbook where 

import System.IO
import System.Directory
        
-- ----------------------------------------
-- ----------- Struktury ------------------
-- ----------------------------------------

-- Przedmiot  :  SPOP - programowanie funkcyjne
-- Projekt    :  Ksiazka adresowa
-- Autorzy    :  Sylwester Golawski
--               Krystian Kaniowski

-- -- DATABASE -----------------------------
data Database = DB {
  contactsBase                :: [Contact],  -- kontaty
  groupsBase                  :: [Group]    -- grupy
}

-- -- KONTAKT ------------------------------
data Contact = Contact {
  contactId                   :: Int,     -- id kontaktu
  name                        :: String,  -- imie
  surname                     :: String,  -- nazwisko
  company                     :: String,  -- firma
  phone                       :: String,  -- telefon
  mail                        :: String,  -- email
  birthday                    :: String   -- data urodzin
} deriving (Show, Read, Eq)

-- -- TYPY DANYCH KONTAKTU -----------------
data DataType = NAME | SURNAME | COMPANY | PHONE | MAIL | BIRTHDAY

-- -- GRUPA --------------------------------
data Group = Group {
  groupId                     :: Int,   -- id grup
  groupName                   :: String,   -- nazwa grupy
  groupMembers                :: [Int]    -- id czlonkow grupy
} deriving (Show, Read, Eq)

-- -- TO STRING ----------------------------

contactsToString :: [Contact] -> String
contactsToString [] = ""
contactsToString (x:xs) = contactToString x ++ contactsToString xs

contactToString :: Contact -> String
contactToString (Contact id name surname company phone mail birthday) = show id ++ " | " ++ name ++ " | " ++ surname ++ " | " ++ company ++ " | " ++  phone ++ " | " ++ mail ++ " | " ++ birthday ++ "\n"

contactsToString' :: [Contact] -> String
contactsToString' [] = ""
contactsToString' (x:xs) = contactToString' x ++ contactsToString' xs

contactToString' :: Contact -> String
contactToString' (Contact id name surname company phone mail birthday) = show id ++ "|" ++ name ++ "|" ++ surname ++ "|" ++ company ++ "|" ++  phone ++ "|" ++ mail ++ "|" ++ birthday ++ "\n"


groupsToString :: [Group] -> String
groupsToString [] = ""
groupsToString (x:xs) = groupToString x ++ "\n" ++ groupsToString xs 

groupToString :: Group -> String
groupToString x = show ( getGroupId x ) ++ " | " ++ getGroupName x ++ " | " ++ ( show ( getGroupMembers x ) )



groupsToString' :: [Group] -> String
groupsToString' [] = ""
groupsToString' (x:xs) = show ( getGroupId x ) ++ "|" ++ getGroupName x ++ "|" ++ ( show ( getGroupMembers x ) ) ++ "\n" ++ groupsToString' xs 

-- TODO: !!!
-- groupToString :: Group -> String
-- groupToString gr = ""

-- ----------------------------------------
-- ----------- Baza danych ----------------
-- ----------------------------------------

-- KONTAKTY
-- --------------------------------------------------

getContactNextId :: [Contact] -> Int -> Int 
getContactNextId [] id = id
getContactNextId (x:xs) id = if (getContactId x >= id) then getContactNextId xs ( getContactId x +1)
                                                       else getContactNextId xs id

getContactId :: Contact -> Int
getContactId ( Contact { contactId = id } ) = id

getContactById :: [Contact] -> Int -> Contact
getContactById [] _ = (Contact 0 "" "" "" "" "" "")
getContactById (x:xs) id = if getContactId x == id then x
                                                   else getContactById xs id

getContactBirthday :: Contact -> String
getContactBirthday ( Contact { birthday = b } ) = b

insertContact :: [Contact] -> String -> String -> String -> String -> String -> String -> [Contact]
insertContact book name surname company phone mail birthday = book ++ [Contact ( getContactNextId book 1 ) name surname company phone mail birthday]

insertContact' :: [Contact] -> Int -> String -> String -> String -> String -> String -> String -> [Contact]
insertContact' book contactId name surname company phone mail birthday = book ++ [Contact contactId name surname company phone mail birthday]


updateContact :: [Contact] -> Int -> String -> String -> String -> String -> String -> String -> [Contact]
updateContact [] _ _ _ _ _ _ _ = []
updateContact [contact] id name surname company phone mail birthday = if getContactId contact == id then [Contact id name surname company phone mail birthday]
                                                                                                    else [contact]
updateContact (x:xs) id name surname company phone mail birthday = (updateContact [x] id name surname company phone mail birthday) ++ (updateContact xs id name surname company phone mail birthday)

updateContact' :: [Contact] -> Int -> DataType -> String -> [Contact]
updateContact' contacts id datatype value = updateContactHelp contacts ( getContactById contacts id ) datatype value

updateContactHelp :: [Contact] -> Contact -> DataType -> String -> [Contact]
updateContactHelp c (Contact id name surname company phone mail birthday ) datatype value = case datatype of
                                                                                                             NAME -> updateContact c id value surname company phone mail birthday
                                                                                                             SURNAME -> updateContact c id name value company phone mail birthday
                                                                                                             COMPANY -> updateContact c id name surname value phone mail birthday
                                                                                                             PHONE -> updateContact c id name surname company value mail birthday
                                                                                                             MAIL -> updateContact c id name surname company phone value birthday
                                                                                                             BIRTHDAY -> updateContact c id name surname company phone mail value


deleteContact :: [Contact] -> Int -> [Contact]
deleteContact [] id = []
deleteContact [contact] id = if (getContactId contact) == id then [] else [contact]
deleteContact (x:xs) id = (deleteContact [x] id) ++ (deleteContact xs id)

deleteContact' :: [Contact] -> Contact -> [Contact]
deleteContact' [] c = []
deleteContact' [contact] c = if contact == c then [] else [contact]
deleteContact' (x:xs) c = (deleteContact' [x] c) ++ (deleteContact' xs c)

-- GRUPY
-- --------------------------------------------------

-- zwraca id grupy
getGroupId :: Group -> Int
getGroupId ( Group { groupId = id } ) = id

-- zwraca nazwe grupy
getGroupName :: Group -> String
getGroupName ( Group { groupName = name } ) = name

-- zwraca czlonkow grupy
getGroupMembers :: Group -> [Int]
getGroupMembers ( Group { groupMembers = memebers } ) = memebers

-- Zwraca grupe po id
getGroupById :: [Group] -> Int -> Group
getGroupById [] _ = ( Group 0 "brak" [] )
getGroupById (x:xs) id = if getGroupId x == id then x
                                               else getGroupById xs id

-- zwraca grupe po nazwie
getGroupByName :: [Group] -> String -> [Group]
getGroupByName [] _ = []
getGroupByName (x:xs) name = if getGroupName x == name then [x]
                                                       else getGroupByName xs name

-- zwraca wolne id, które można użyc do stworzenia nowej grupy
getGroupNextId :: [Group] -> Int -> Int 
getGroupNextId [] id = id
getGroupNextId (x:xs) id = if (getGroupId x >= id) then getGroupNextId xs ( getGroupId x +1)
                                                   else getGroupNextId xs id

-- zwraca prawde jeżeli obiekt o podanym id istnieje w grupie
existed :: [Group] -> Int -> Bool
existed [] _ = False
existed (x:xs) id = if getGroupId x == id then True
                                       else existed xs id

-- wstawia grupe do bazy danych
insertGroup :: [Group] -> String -> [Group]
insertGroup groups name = groups ++ [Group (getGroupNextId groups 1 ) name []]

insertGroup' :: [Group] -> Int -> String -> [Int] -> [Group]
insertGroup' groups groupId name members= groups ++ [Group groupId name members]


-- scala dwie grupy i nadaje nowa nazwe
sumGroup :: [Group] -> Int -> Int -> String -> [Group]
sumGroup [] _ _ _ = []
sumGroup groups id1 id2 name = if ( existed groups id1 && existed groups id2 )
                                  then 
                                     do let y = getGroupMembers ( getGroupById groups id2 )
                                        updateGroup' ( deleteGroup groups id2 ) id1 name ( removeDuplicates (getGroupMembers ( getGroupById groups id1 ) ++ y ) )
                                  else error "nie ma elementow o takich id"

removeDuplicates :: [Int] -> [Int]
removeDuplicates [] = []
removeDuplicates (x:xs) = x : removeDuplicates (filter (\y -> not (x == y)) xs)

-- aktualizuje nazwe grupy
updateGroup :: [Group] -> Int -> String -> [Group]
updateGroup [] _ _ = []
updateGroup [groups] id name = if ( getGroupId groups ) == id then [Group id name ( getGroupMembers groups ) ]
                                                          else [groups]
updateGroup (x:xs) id name = ( updateGroup [x] id name ) ++ ( updateGroup xs id name )

-- aktualizuje nazwe i czlonkow grupy
updateGroup' :: [Group] -> Int -> String -> [Int] -> [Group]
updateGroup' [] _ _ _ = []
updateGroup' [groups] id name members = if ( getGroupId groups ) == id then [Group id name members  ]
                                                          else [groups]
updateGroup' (x:xs) id name members = ( updateGroup' [x] id name members ) ++ ( updateGroup' xs id name members )

-- usuwa grupe o podanym id
deleteGroup :: [Group] -> Int -> [Group]
deleteGroup [] id = []
deleteGroup [groups] id = if ( getGroupId groups ) == id then []
                                                         else [groups]
deleteGroup (x:xs) id = ( deleteGroup [x] id ) ++ ( deleteGroup xs id )

-- usuwa grupe
deleteGroup' :: [Group] -> Group -> [Group]
deleteGroup' [] gr = []
deleteGroup' [groups] gr = if gr == groups then []
                                          else [groups]
deleteGroup' (x:xs) id = ( deleteGroup' [x] id ) ++ ( deleteGroup' xs id )


-- dodaje czlonka do grupy
-- TODO: walidacja, czy gosc juz nie jest w grupie

addMemeber :: [Group] -> Int -> Int -> [Group]
addMemeber groups groupId contactId = updateGroup' groups groupId ( getGroupName ( getGroupById groups groupId ) ) ( addMemeberHelp groups groupId contactId )

addMemeberHelp :: [Group] -> Int -> Int -> [Int]
addMemeberHelp groups groupId contactId = removeDuplicates ( getGroupMembers ( getGroupById groups groupId ) ++ [contactId] )

--
removeMembers :: [Group] -> Int -> Int -> [Group]
removeMembers [] _ _ = groups
removeMembers [groups] groupId contId = if ( getGroupId groups ) == groupId then [Group groupId ( getGroupName groups ) ( removeMembersHelp ( getGroupMembers groups ) contId )]
                                                                               else [groups]
removeMembers (x:xs) groupId contactId = ( removeMembers [x] groupId contactId ) ++ ( removeMembers xs groupId contactId )

removeMembersHelp :: [Int] -> Int -> [Int]
removeMembersHelp [] _ = []
removeMembersHelp (x:xs) id = if ( x == id ) then [] ++ removeMembersHelp xs id
                                             else [x] ++ removeMembersHelp xs id

-- pokazuje czlonkow grupy 
showMembers :: [Contact] -> [Group] -> Int -> String
showMembers book groups groupId = contactsIdToDescription book ( getGroupMembers( getGroupById groups groupId ) )

contactsIdToDescription :: [Contact] -> [Int] -> String
contactsIdToDescription book [] = []
contactsIdToDescription book (x:xs) = contactToString( getContactById book x ) ++ contactsIdToDescription book xs

listFindMemebersGroups :: [Contact] -> [Group] -> [Group] -> String                         
listFindMemebersGroups _ [] _ = ""
listFindMemebersGroups _ _ [] = ""
listFindMemebersGroups contacts groups [x] = contactsIdToDescription book ( getGroupMembers x ) 
listFindMemebersGroups contacts groups ( x:xs ) = groupToString x ++ ":\n\n" ++ listFindMemebersGroups contacts groups [x] ++ listFindMemebersGroups contacts groups xs
                      

-- ----------------------------------------
-- ----------- Szukajki -------------------
-- ----------------------------------------

-- -- Szukajki -----------------------------

-- Zwraca konkretna dana z kontaktu po typie

getByType :: Contact -> DataType -> String
getByType (Contact id name surname company phone mail birthday) datatype = case datatype of
                                                                                        NAME -> name
                                                                                        SURNAME -> surname
                                                                                        COMPANY -> company
                                                                                        PHONE -> phone
                                                                                        MAIL -> mail
                                                                                        BIRTHDAY -> birthday

-- Znajduje kontakt po tagu i wartosci

findBy :: DataType -> [Contact] -> String -> [Contact]
findBy datatype [] value = []
findBy datatype (x:xs) value = if getByType x datatype == value then [x] ++ findBy datatype xs value
                                                                else findBy datatype xs value

-- zwraca kto ma dzisiaj urodziny
-- TODO: Kto ma dzisij urodziny
-- date :: IO (Integer,Int,Int) -- :: (year,month,day)
-- date = getCurrentTime >>= return . toGregorian . utctDay
--wannaParty book 

-- Przykladowe dane

osoba1 = Contact 0 "Krystian" "nazwisko" "firma" "telefon" "mail" "04-06-2012"
osoba2 = Contact 1 "Karola" "nazwisko" "firma" "telefon" "mail" "4-06-2341"
osoba3 = Contact 2 "Michal" "nazwisko" "firma" "telefon" "mail" "4-6-1345"

book = [ osoba1, osoba2, osoba3 ] 

group1 = Group 1 "test" [1,2,3]
group2 = Group 2 "test2" [1,2,3]

groups = [group1, group2]






                                                        



                                        
                                            

                                  
                 

